/*
 * JudgeD.cpp
 *
 *  Created on: 2012-11-16
 *      Author: kidlet
 */


#include "head.h"
#include "var.h"

int main ()
{
	if (Intial ())
	{
		printf( "初始化程序失败, 请检查配置文件\n" );
		return 0;
	}

	while ( Intial_MySQL () )
	{
		printf("%s 连接数据库出错， 将等待10秒后重新连接\n", GetDateTime ("%Y-%m-%d %X%p"));
		sleep (10);
	}

	printf("%s 判题调度程序正常启动， 开始调度中...\n", GetDateTime ("%Y-%m-%d %X%p"));
	//Run_Judger ();

	while (1)
	{
		Run_Judger ();
		sleep (10);
	}

	Call_Exit (0);
	return 0;
}

int Intial ()
{
	//------------------- 读取配置文件参数----------------------------------
	int ret=0;
	ret += ReadParameter ( "Mysql_Address" , Mysql_Address );
	ret += ReadParameter ( "Mysql_Username" , Mysql_Username );
	ret += ReadParameter ( "Mysql_Password" , Mysql_Password );
	ret += ReadParameter ( "OJ_Home" , OJ_Home );
	ret += ReadParameter ( "Judger_Path" , Judger_Path );
	ret += ReadParameter ( "Database" , DB );
	ret += ReadParameter ( "JudgerMaxNum" , str_tmp );

	if ( ret!=0 )
	{
		printf("%s 读取配置信息出错\n", GetDateTime ("%Y-%m-%d %X%p") );
		//Write log
		return 1;
	}
	sscanf ( str_tmp, "%d", &JudgerMaxNum );
	mysql = NULL;

	signal(SIGQUIT, Call_Exit );
	signal(SIGKILL, Call_Exit );
	signal(SIGTERM, Call_Exit );

	return 0;

}

int Intial_MySQL ()
{
	//------------------- MySQL数据库链接--------------------------------
	if ( mysql != NULL )
		mysql_close(mysql);

	mysql = mysql_init( NULL );	//如果参数为NULL 则分配一个
	if ( mysql == NULL )
		return 1;
	const char timeout = 30;
	mysql_options( mysql, MYSQL_OPT_CONNECT_TIMEOUT, &timeout);
	
	if ( mysql_real_connect ( mysql, Mysql_Address, Mysql_Username, Mysql_Password,  DB, 0, NULL, 0 ) == NULL )
		return 1;
	return mysql_query( mysql, "set names utf8" );	//设置获取字符集 以适应中文
}
int ReadParameter ( const char pName [BUFFER_SIZE], char result [BUFFER_SIZE])
{
	FILE* file;
	file = fopen ( CONF, "r" );
	if ( file == NULL )
	{
		printf("%s 打开配置文件失败\n", GetDateTime ("%Y-%m-%d %X%p"));
		//Write log
		return 1;
	}

	char str [BUFFER_SIZE];
	char name [BUFFER_SIZE], value [BUFFER_SIZE];
	int flag=0, i;	//标志是否找到
	memset ( value, 0, sizeof(value));		//初始化为空

	while ( fgets ( str, BUFFER_SIZE, file ) )
	{
		if ( str [0] == '#' )				//跳过注释行
			continue;

		memset ( name, 0, sizeof(name));	//初始化为空

		for ( i=0; str[i]; i++ )
			if ( str [i] == '=' )	break;
		if ( str [i] == 0 )					//找不到“=”
			continue;

		for ( int j=0; j<i; j++ )
			name [j] = str [j];
		name [i] = 0;

		if ( strcmp ( name, pName ) == 0 )
		{
			flag = 1;
			for ( int j=i+1; str[j]; j++ )
				value [j-i-1] = str [j];
			break;
		}
	}

	if ( flag==0 )
		return 1;

	value [strlen(value)-1] = 0;			//去掉结尾多余的 \n;
	strcpy ( result, value );
	fclose ( file );
	return 0;
}

int WriteLog ( const char *fName, const char *data )
{
	string str ( OJ_Home );
	str.append ( "/" );	str.append ( fName );
	
	FILE *file;
	file = fopen ( str.data(), "a");
	if ( file == NULL )
	{
		printf("%s 打开日志文件失败\n", GetDateTime ("%Y-%m-%d %X%p") );
		return 1;

	}
	if ( fputs ( data, file ) == EOF )
		return 1;
	return 0;
}

const char*  GetDateTime ( const char* format )
{
	time_t a = time(NULL);
	strftime ( str_tmp, BUFFER_SIZE-1, format, localtime ( &a ) );
	return str_tmp;
}

void Call_Exit ( int signal )
{
	mysql_close(mysql);
	printf ( "判题调度程序被中止\n" );
	exit (0);
}


void Run_Judger ()
{
	int pid, status;
	GetJobs ();
	for ( int i=0; i<JobsCnt; i++ )
	{
		if ( RuningNum >= JudgerMaxNum )		//如果超出Judger数量则阻塞自己直到有一个Judger结束
		{
			wait (&status);
			RuningNum--;
		}

		pid = fork ();
		RuningNum++;
		if ( pid == 0 )
		{
			sprintf ( str_tmp, "%d", Jobs [i] );
			execl ( Judger_Path, str_tmp, NULL );
			exit (0);
		}
	}

	while ( RuningNum>0 )
	{
		wait (&status);
		RuningNum--;
	}

}

int GetJobs ()
{
	MYSQL_RES *res;
	MYSQL_ROW row;
	char query[BUFFER_SIZE];
	int ret;

	sprintf ( query, "SELECT solution_id FROM  think_queue ORDER BY (in_date) LIMIT %d", BUFFER_SIZE-1 );
	
	ret = mysql_query ( mysql, query );
	if ( ret )	return 1;
	res = mysql_store_result( mysql );

	JobsCnt = 0;
	while ( (row = mysql_fetch_row(res)) )
	{
		Jobs [JobsCnt++] = atoi(row [0]);
	}

	mysql_free_result ( res );
	return 0;
}
